package net.guerlab.smart.qcloud.im;

import com.fasterxml.jackson.databind.ObjectMapper;
import lombok.Getter;
import lombok.Setter;
import lombok.extern.slf4j.Slf4j;

import java.lang.reflect.ParameterizedType;
import java.util.HashMap;
import java.util.Map;

/**
 * 抽象请求数据
 *
 * @param <R>
 *         响应数据类型
 * @author guer
 */
@Setter
@Getter
@Slf4j
public abstract class AbstractImRequest<R extends AbstractImResponse> {

    /**
     * 获取响应对象类型
     *
     * @return 响应对象类型
     */
    @SuppressWarnings("unchecked")
    private Class<R> getResponseClass() {
        return (Class<R>) ((ParameterizedType) getClass().getGenericSuperclass()).getActualTypeArguments()[0];
    }

    /**
     * 解析响应数据
     *
     * @param responseData
     *         响应数据
     * @param objectMapper
     *         objectMapper
     * @return 响应类
     */
    public final R parseResponse(String responseData, ObjectMapper objectMapper) {
        log.debug("origin responseData: {}", responseData);
        R response;
        try {
            Class<R> rClass = getResponseClass();
            response = objectMapper.readValue(responseData, rClass);
        } catch (Exception e) {
            throw new ImException("response body parse fail", e);
        }

        if (response == null) {
            throw new ImException("response body is empty");
        }

        parseResponseAfter(response);

        return response;
    }

    /**
     * 响应解析后置环绕，用于处理复杂响应
     *
     * @param response
     *         响应
     */
    @SuppressWarnings({ "EmptyMethod", "unused" })
    protected void parseResponseAfter(R response) {
        /*
         * 默认情况下不做额外处理
         */
    }

    /**
     * 获取请求地址
     *
     * @return 请求地址
     */
    public abstract String uri();

    /**
     * 获取请求正文内容
     *
     * @param objectMapper
     *         objectMapper
     * @return 请求正文内容
     */
    public abstract byte[] requestBody(ObjectMapper objectMapper);

    /**
     * 获取请求地址查询参数
     *
     * @return 请求地址查询参数
     */
    public Map<String, String> query() {
        return new HashMap<>(8);
    }
}
